from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.db.postgres import get_session
from app.schemas.network_volume import CollectResult, AggregatesRead, EvidenceList, EvidenceItem, CollectionConfigRead, CollectionConfigUpdate
from app.models import Activity, NetworkVolumeEvidence, Evaluation, ActivityCollectionConfig
from app.services.network_volume.collectors.news import collect_news
from app.services.network_volume.collectors.weibo import collect_weibo
from app.services.network_volume.collectors.douyin import collect_douyin
from app.services.network_volume.collectors.kuaishou import collect_kuaishou
from app.services.network_volume.collectors.xhs import collect_xhs
from app.services.network_volume.collectors.wechat import collect_wechat
from app.services.network_volume.aggregate import compute_aggregates
from app.services.network_volume.scoring import compute_network_volume_scores
from app.services.network_volume.scoring import compute_growth_rate_from_series
from app.services.scoring import compute_evaluation_total
from app.services.network_volume.providers.weibo_api import fetch_weibo_keyword_series
from app.services.network_volume.providers.douyin_api import fetch_douyin_keyword_series
from app.config import settings
import os
import httpx


router = APIRouter(prefix="/network-volume", tags=["network-volume"])


@router.post("/activities/{activity_id}/collect", response_model=CollectResult)
async def collect(activity_id: str, session: AsyncSession = Depends(get_session)):
    act = await session.get(Activity, activity_id)
    if not act:
        raise HTTPException(status_code=404, detail="活动不存在")
    cfg_q = await session.execute(select(ActivityCollectionConfig).where(ActivityCollectionConfig.activity_id == activity_id))
    cfg = cfg_q.scalars().first()
    cfg_keywords = []
    cfg_accounts = {}
    if cfg and cfg.keywords_json:
        try:
            import json
            cfg_keywords = json.loads(cfg.keywords_json)
        except Exception:
            cfg_keywords = []
    if cfg and cfg.accounts_json:
        try:
            import json
            cfg_accounts = json.loads(cfg.accounts_json)
        except Exception:
            cfg_accounts = {}
    n1 = await collect_news(session, activity_id)
    n2 = await collect_weibo(session, activity_id, cfg_keywords, cfg_accounts)
    n3 = await collect_douyin(session, activity_id, cfg_keywords, cfg_accounts)
    n4 = await collect_kuaishou(session, activity_id, cfg_keywords, cfg_accounts)
    n5 = await collect_xhs(session, activity_id, cfg_keywords, cfg_accounts)
    n6 = await collect_wechat(session, activity_id, cfg_keywords, cfg_accounts)
    kw = None
    if cfg_keywords and isinstance(cfg_keywords, list) and cfg_keywords:
        kw = str(cfg_keywords[0])
    if not kw:
        kw = act.name or ''
    growth_val = 0.0
    try:
        wb_series = await fetch_weibo_keyword_series(kw)
        from app.services.network_volume.scoring import compute_growth_rate_from_series
        g1 = compute_growth_rate_from_series(wb_series)
        dy_series = await fetch_douyin_keyword_series(kw)
        g2 = compute_growth_rate_from_series(dy_series)
        vals = [x for x in [g1, g2] if x and x > 0]
        if vals:
            growth_val = sum(vals) / len(vals)
    except Exception:
        growth_val = 0.0
    if growth_val != 0.0:
        from app.models import NetworkVolumeAggregate
        row_q = await session.execute(
            select(NetworkVolumeAggregate).where(
                NetworkVolumeAggregate.activity_id == activity_id,
                NetworkVolumeAggregate.metric_key == 'index_growth_rate'
            )
        )
        row = row_q.scalars().first()
        if row:
            row.value = growth_val
        else:
            obj = NetworkVolumeAggregate(activity_id=activity_id, metric_key='index_growth_rate', value=growth_val)
            session.add(obj)
        await session.flush()
    await compute_aggregates(session, activity_id)
    return CollectResult(collected_news=n1, collected_weibo=n2)


@router.get("/activities/{activity_id}/aggregates", response_model=AggregatesRead)
async def aggregates(activity_id: str, session: AsyncSession = Depends(get_session)):
    await compute_aggregates(session, activity_id)
    result = await session.execute(select(Activity).where(Activity.id == activity_id))
    if not result.scalars().first():
        raise HTTPException(status_code=404, detail="活动不存在")
    aggs = await compute_aggregates(session, activity_id)
    # 补充详情：从聚合表取出社交平台细分
    from app.models import NetworkVolumeAggregate
    row_q = await session.execute(
        select(NetworkVolumeAggregate).where(
            NetworkVolumeAggregate.activity_id == activity_id,
            NetworkVolumeAggregate.metric_key == 'social_total_interactions'
        )
    )
    row = row_q.scalars().first()
    details = None
    if row and row.details_json:
        try:
            details = eval(row.details_json)
        except Exception:
            details = None
    return AggregatesRead(**aggs, details=details)


@router.get("/activities/{activity_id}/evidence", response_model=EvidenceList)
async def evidence(activity_id: str, session: AsyncSession = Depends(get_session)):
    result = await session.execute(select(NetworkVolumeEvidence).where(NetworkVolumeEvidence.activity_id == activity_id))
    items = [EvidenceItem.model_validate(x) for x in result.scalars().all()]
    return EvidenceList(items=items)


@router.post("/activities/{activity_id}/evidence/snapshot", response_model=EvidenceItem)
async def save_snapshot(activity_id: str, payload: dict, session: AsyncSession = Depends(get_session)):
    from app.models import NetworkVolumeEvidence
    act = await session.get(Activity, activity_id)
    if not act:
        raise HTTPException(status_code=404, detail="活动不存在")
    t = str(payload.get('type') or 'html')
    url = str(payload.get('path_or_url') or '')
    if not url:
        raise HTTPException(status_code=400, detail="缺少URL")
    base_dir = os.path.join(str(settings.reports_dir), 'network_volume', str(activity_id))
    os.makedirs(base_dir, exist_ok=True)
    file_path = os.path.join(base_dir, f"snapshot_{abs(hash(url))}.html")
    try:
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.get(url)
            content = resp.text
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(content)
        item = NetworkVolumeEvidence(activity_id=activity_id, type=t, path_or_url=file_path, meta_json=str({"source_url": url}))
        session.add(item)
        await session.flush()
        await session.refresh(item)
        await session.commit()
        return EvidenceItem.model_validate(item)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"快照保存失败: {e}")


@router.post("/evaluations/{evaluation_id}/auto-score")
async def auto_score(evaluation_id: str, session: AsyncSession = Depends(get_session)):
    ev = await session.get(Evaluation, evaluation_id)
    if not ev:
        raise HTTPException(status_code=404, detail="评估不存在")
    scores = await compute_network_volume_scores(session, evaluation_id, {'activity_id': str(ev.activity_id)})
    total = await compute_evaluation_total(session, evaluation_id)
    return {"scores": scores, "total": float(total)}


@router.get("/activities/{activity_id}/trend")
async def trend(activity_id: str, source: str = 'weibo', keyword: str | None = None, session: AsyncSession = Depends(get_session)):
    act = await session.get(Activity, activity_id)
    if not act:
        raise HTTPException(status_code=404, detail="活动不存在")
    kw = keyword or ''
    if not kw:
        cfg_q = await session.execute(select(ActivityCollectionConfig).where(ActivityCollectionConfig.activity_id == activity_id))
        cfg = cfg_q.scalars().first()
        if cfg and cfg.keywords_json:
            try:
                import json
                arr = json.loads(cfg.keywords_json)
                if isinstance(arr, list) and arr:
                    kw = str(arr[0])
            except Exception:
                kw = ''
    if not kw:
        kw = act.name or ''
    series: list[dict] = []
    if source == 'weibo':
        series = await fetch_weibo_keyword_series(kw)
    elif source == 'douyin':
        series = await fetch_douyin_keyword_series(kw)
    else:
        series = []
    growth = compute_growth_rate_from_series(series)
    return {"source": source, "keyword": kw, "series": series, "growth_rate": growth}


@router.get("/activities/{activity_id}/config", response_model=CollectionConfigRead)
async def get_config(activity_id: str, session: AsyncSession = Depends(get_session)):
    act = await session.get(Activity, activity_id)
    if not act:
        raise HTTPException(status_code=404, detail="活动不存在")
    result = await session.execute(select(ActivityCollectionConfig).where(ActivityCollectionConfig.activity_id == activity_id))
    obj = result.scalars().first()
    if not obj:
        return CollectionConfigRead(activity_id=activity_id, keywords_json=None, accounts_json=None)
    return CollectionConfigRead(activity_id=activity_id, keywords_json=obj.keywords_json, accounts_json=obj.accounts_json)


@router.post("/activities/{activity_id}/config", response_model=CollectionConfigRead)
async def set_config(activity_id: str, payload: CollectionConfigUpdate, session: AsyncSession = Depends(get_session)):
    act = await session.get(Activity, activity_id)
    if not act:
        raise HTTPException(status_code=404, detail="活动不存在")
    import json
    kw_json = json.dumps(payload.keywords or [])
    acc_json = json.dumps(payload.accounts or {})
    result = await session.execute(select(ActivityCollectionConfig).where(ActivityCollectionConfig.activity_id == activity_id))
    obj = result.scalars().first()
    if obj:
        obj.keywords_json = kw_json
        obj.accounts_json = acc_json
    else:
        obj = ActivityCollectionConfig(activity_id=activity_id, keywords_json=kw_json, accounts_json=acc_json)
        session.add(obj)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return CollectionConfigRead(activity_id=activity_id, keywords_json=obj.keywords_json, accounts_json=obj.accounts_json)
